//--------------------------------------------------------------------------------------
// File: DXshader.fx
//
// The effect file for the CRT application
// 
// Wenle WANG
//--------------------------------------------------------------------------------------


//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float3 g_vMaterialAmbient	: Ambient = float3( 0.2f, 0.2f, 0.2f );   // Material's ambient color
float3 g_vMaterialDiffuse	: Diffuse = float3( 0.6f, 0.6f, 0.6f );   // Material's diffuse color
float3 g_vMaterialSpecular	: Specular = float3( 1.0f, 1.0f, 1.0f );  // Material's specular color
float  g_fMaterialAlpha		: Opacity = 1.0f;
int    g_nMaterialShininess : SpecularPower = 32;

float3 g_vLightColor		: LightColor = float3( 1.0f, 1.0f, 1.0f );  // Light color
float3 g_vLightDirection	: LightDirection = float3( 0, -1, 0 );		// Light direction
float3 g_vCameraPosition	: CameraPosition;
bool   g_bInvertDepthFunc = false;
float  g_fDepthBias			: DepthBias = 0.004f;

texture	 g_RTT : Texture;			// Render to texture 
            
float4x4 g_mWorld : World;								// World matrix
float4x4 g_mWorldViewProjection : WorldViewProjection;	// World * View * Projection matrix
float4x4 g_mWorldToShadowMap : WorldToShadowMap;		// Matrix from world space to shadow map texture space, used for Shadowing pass

float4	g_vSampleOffset[64];
float4	g_vFrustumColor;


//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler RTTSampler = 
sampler_state
{
	Texture = <g_RTT>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
	ADDRESSU = BORDER;
	ADDRESSV = BORDER;
	BORDERCOLOR = 0xffffffff;
};


//--------------------------------------------------------------------------------------
// Name: VS_NoShadow
// Type: Vertex Shader Fragment
// Desc: Projection transform
//--------------------------------------------------------------------------------------
void VS_NoShadow( float4 vPosObject: POSITION,
                 float3 vNormalObject: NORMAL,
                 float2 vTexCoordIn: TEXCOORD0,
                 out float4 vPosProj: POSITION,
                 out float2 vTexCoordOut: TEXCOORD0,
                 out float3 vNormalOut : TEXCOORD1,
                 out float3 vPosWorldOut : TEXCOORD2
                )
{
    // Transform the position into world space for lighting, and projected space
    // for display
    float4 vPosWorld = mul( vPosObject, g_mWorld );
    vPosProj = mul( vPosObject, g_mWorldViewProjection );
    
    // Transform the normal into world space for lighting
    float3 vNormalWorld = mul( vNormalObject, (float3x3)g_mWorld );
    
    // Pass the texture coordinate
    vTexCoordOut = vTexCoordIn;
    
    // Pass the normal in world space
    vNormalOut = vNormalWorld;
    
    // Pass the world position
    vPosWorldOut = vPosWorld;
}



//--------------------------------------------------------------------------------------
// Name: PS_NoShadow
// Type: Pixel Shader
// Desc: Compute lighting and modulate the texture
//--------------------------------------------------------------------------------------
void PS_NoShadow( float2 vTexCoord: TEXCOORD0,
               float3 vNormal: TEXCOORD1,
               float3 vPosWorld: TEXCOORD2,
               out float4 vColorOut: COLOR0)
{  
    // Compute the ambient and diffuse components of illumination
    vColorOut.rgb = g_vLightColor * g_vMaterialAmbient;
    vColorOut.rgb += g_vLightColor * g_vMaterialDiffuse * saturate( dot( -g_vLightDirection, vNormal ) );
    vColorOut.a = g_fMaterialAlpha;
    
    
    // Calculate the specular term
    float3 vCamera = normalize( vPosWorld - g_vCameraPosition );
    float3 vReflection = reflect( -g_vLightDirection, vNormal );
    float  fPhongValue = saturate( dot( vReflection, vCamera ) );

    vColorOut.rgb += g_vMaterialSpecular * pow(fPhongValue, g_nMaterialShininess);
    vColorOut.a = g_fMaterialAlpha;
}



//--------------------------------------------------------------------------------------
// Name: VS_Shadow
// Type: Vertex Shader Fragment
// Desc: Projection transform
//--------------------------------------------------------------------------------------
void VS_Shadow( float4 vPosObject: POSITION,
                 float3 vNormalObject: NORMAL,
                 float2 vTexCoordIn: TEXCOORD0,
                 out float4 vPosProj: POSITION,
                 out float2 vTexCoordOut: TEXCOORD0,
                 out float3 vNormalOut : TEXCOORD1,
                 out float3 vPosWorldOut : TEXCOORD2,
                 out float4 vPosLightPPS : TEXCOORD3
                )
{
    // Transform the position into world space for lighting, and projected space
    // for display
    float4 vPosWorld = mul( vPosObject, g_mWorld );
    vPosProj = mul( vPosObject, g_mWorldViewProjection );
    
    // Transform the normal into world space for lighting
    float3 vNormalWorld = mul( vNormalObject, (float3x3)g_mWorld );
    
    // Pass the texture coordinate
    vTexCoordOut = vTexCoordIn;
    
    // Pass the normal in world space
    vNormalOut = vNormalWorld;
    
    // Pass the world position
    vPosWorldOut = vPosWorld;
    
    // Transform the vertex into light's perspective space
    vPosLightPPS = mul( float4(vPosWorld.xyz, 1), g_mWorldToShadowMap );
}

//--------------------------------------------------------------------------------------
// Name: PS_Shadow
// Type: Pixel Shader
// Desc: Compute lighting and modulate the texture
//--------------------------------------------------------------------------------------
void PS_Shadow( float2 vTexCoord: TEXCOORD0,
               float3 vNormal: TEXCOORD1,
               float3 vPosWorld: TEXCOORD2,
               float4 vPosLightPPS : TEXCOORD3,
               out float4 vColorOut: COLOR0, 
               uniform int SampleNum)
{  
    // Shadow Mask
    float	ShadowMask = 0;	// 1 for non-shadow, 0 for shadow

    // In light's perspective space, perform perspective correction
    vPosLightPPS /= vPosLightPPS.w;    
    
    for (int i = 0; i < SampleNum; i++)
    {
		float ShadowTexDepth = tex2D( RTTSampler, vPosLightPPS + g_vSampleOffset[i] ).r;
   		ShadowMask += (vPosLightPPS.z <= ShadowTexDepth + g_fDepthBias) * g_vSampleOffset[i].z; 
   	}

    // Compute the ambient and diffuse components of illumination
    float3	Ambient		= g_vLightColor * g_vMaterialAmbient;
    float3	Diffuse		= g_vLightColor * g_vMaterialDiffuse * saturate( dot( -g_vLightDirection, vNormal ) );
    
    // Calculate the specular term
    float3 vCamera = normalize( vPosWorld - g_vCameraPosition );
    float3 vReflection = reflect( -g_vLightDirection, vNormal );
    float  fPhongValue = saturate( dot( vReflection, vCamera ) );    
    float3	Specular	= g_vMaterialSpecular * pow(fPhongValue, g_nMaterialShininess);
    
    vColorOut.rgb	= Ambient + ShadowMask * (Diffuse + Specular);
    vColorOut.a		= g_fMaterialAlpha;
}


//--------------------------------------------------------------------------------------
// Name: VS_RenderRTT
// Type: Vertex Shader Fragment
// Desc: Projection transform
//--------------------------------------------------------------------------------------
void VS_RenderRTT( float4 vPosObj: POSITION,
				   float2 vTexCoord : TEXCOORD0,
				   out float4 vPosProj: POSITION,
				   out float2 vTexCoordOut: TEXCOORD0
				 )
{
	vPosProj = mul( vPosObj, g_mWorldViewProjection );
	vTexCoordOut = vTexCoord;
}


//--------------------------------------------------------------------------------------
// Name: PS_RenderRTT
// Type: Pixel Shader
// Desc: Simplely output the light color
//--------------------------------------------------------------------------------------
void PS_RenderRTT( float2 vTexCoord: TEXCOORD0,
				   out float4 vColorOut: COLOR0 )
{
	vColorOut = abs(float4(tex2D( RTTSampler, vTexCoord ).rrr, 0.7f));
}


//--------------------------------------------------------------------------------------
// Name: VS_RenderFrustum
// Type: Vertex Shader Fragment
// Desc: Projection transform
//--------------------------------------------------------------------------------------
void VS_RenderFrustum( float4 vPosObj: POSITION,
				   out float4 vPosProj: POSITION
				 )
{
	vPosProj = mul( vPosObj, g_mWorldViewProjection );
}


//--------------------------------------------------------------------------------------
// Name: PS_RenderFrustum
// Type: Pixel Shader
// Desc: Simplely output the light color
//--------------------------------------------------------------------------------------
void PS_RenderFrustum( out float4 vColorOut: COLOR0 )
{
	vColorOut = g_vFrustumColor;
}



//--------------------------------------------------------------------------------------
// Name: VS_GenShadow
// Type: Vertex Shader Fragment
// Desc: Projection transform
//--------------------------------------------------------------------------------------
void VS_GenShadow( float4 vPosObj: POSITION,
				   out float4 vPosProj: POSITION,
				   out float4 vPosProjMirror: TEXCOORD0
				 )
{
	vPosProj		= mul( vPosObj, g_mWorldViewProjection );
	vPosProjMirror	= vPosProj;
}


//--------------------------------------------------------------------------------------
// Name: PS_GenShadow
// Type: Pixel Shader
// Desc: Simplely output the light color
//--------------------------------------------------------------------------------------
void PS_GenShadow(  float4 vPosProj: TEXCOORD0,
					out float4 vColorOut: COLOR0 )
{
	float Depth = vPosProj.z / vPosProj.w;	// Depth value in post perspetive space
	
	// PSM sometimes reverts the depth value
	if (g_bInvertDepthFunc)
		Depth = -Depth;
	vColorOut = float4(Depth, Depth, Depth, Depth);	
}


//--------------------------------------------------------------------------------------
// Techniques
//--------------------------------------------------------------------------------------
technique NoShadow
{
    pass P0
    {
        VertexShader = compile vs_2_0 VS_NoShadow();    
        PixelShader = compile ps_2_0 PS_NoShadow();
    }
}

technique UseShadow_1x1
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_2_0 PS_Shadow(1);
	}
}
technique UseShadow_2x2
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_2_0 PS_Shadow(4);
	}
}
technique UseShadow_3x3
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_2_0 PS_Shadow(9);
	}
}
technique UseShadow_4x4
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_3_0 PS_Shadow(16);
	}
}
technique UseShadow_5x5
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_3_0 PS_Shadow(25);
	}
}
technique UseShadow_6x6
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_3_0 PS_Shadow(36);
	}
}
technique UseShadow_7x7
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_3_0 PS_Shadow(49);
	}
}
technique UseShadow_8x8
{
	pass P0
	{
		VertexShader	= compile vs_2_0 VS_Shadow();
		PixelShader		= compile ps_3_0 PS_Shadow(64);
	}
}

technique RenderRTT
{
	pass P0
	{
		VertexShader = compile vs_2_0 VS_RenderRTT();
		PixelShader	 = compile ps_2_0 PS_RenderRTT();
	}
}

technique RenderFrustum
{
	pass P0
	{
		VertexShader = compile vs_2_0 VS_RenderFrustum();
		PixelShader	 = compile ps_2_0 PS_RenderFrustum();
	}
}

technique GenShadow
{
	pass P0
	{
		VertexShader = compile vs_2_0 VS_GenShadow();
		PixelShader	 = compile ps_2_0 PS_GenShadow();
	}
}
